ARouter 源码详解一

ARouter 源码详解一

ARouter 的源码提供两个 SDK ,分别是面向不同的阶段,本身 API 这个 SDK 是面向运行期的 ,而 compiler 这个 SDK 则是作用于编译期的,我们首先分析一下 compiler 这个 SDK

BaseProcessor

这是注解处理器的基类,主要进行一些工具类的初始化还有一些赋值操作,源码如下:

public abstract class BaseProcessor extends AbstractProcessor {
    Filer mFiler;
    Logger logger;
    Types types;
    Elements elementUtils;
    TypeUtils typeUtils;
    // Module name, maybe its 'app' or others
    String moduleName = null;
    // If need generate router doc
    boolean generateDoc;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);

        mFiler = processingEnv.getFiler();
        types = processingEnv.getTypeUtils();
        elementUtils = processingEnv.getElementUtils();
        typeUtils = new TypeUtils(types, elementUtils);
        logger = new Logger(processingEnv.getMessager());


        Map<String, String> options = processingEnv.getOptions();
        if (MapUtils.isNotEmpty(options)) {
            // 获取用户配置的 moduleName    
            moduleName = options.get(KEY_MODULE_NAME);
            // 是否需要生成路由表文档
            generateDoc = VALUE_ENABLE.equals(options.get(KEY_GENERATE_DOC_NAME));
        }

        ...
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedOptions() {
        return new HashSet<String>() {{
	            this.add(KEY_MODULE_NAME);
	            this.add(KEY_GENERATE_DOC_NAME);
	        }};
    }
}

这个基类主要是初始化工具类,比如 Filer、TypeUtils、Logger 等和获取用户配置的 moduleNamegenerateDoc
我们先看一下当初使用时是怎样配置的:

android {
    defaultConfig {
        ...
        //ARouter 配置
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ AROUTER_MODULE_NAME : project.getName(), AROUTER_GENERATE_DOC: "enable"]
            }
        }
    }
}

很明显,基类就是对这两个值进行的处理,可能你觉得这两个值好像不一样,其实这是一个常量值,在 Consts 类里,我们看一下 Consts 类的部分常量:

// Options of processor
public static final String KEY_MODULE_NAME = "AROUTER_MODULE_NAME";
public static final String KEY_GENERATE_DOC_NAME = "AROUTER_GENERATE_DOC";

public static final String VALUE_ENABLE = "enable";

这些值跟配置里面的一模一样。因为 ARouter 支持多模块工程,所以需要配置模块名称。

InterceptorProcessor

该处理器主要是处理拦截器的,即处理 Interceptor 注解,主要的方法如下:

private void parseInterceptors(Set<? extends Element> elements) throws IOException {
      if (CollectionUtils.isNotEmpty(elements)) {
          logger.info(">>> Found interceptors, size is " + elements.size() + " <<<");

          // Verify and cache, sort incidentally.
          for (Element element : elements) {
              if (verify(element)) {  // Check the interceptor meta
                  logger.info("A interceptor verify over, its " + element.asType());

                  // 获取 Interceptor 注解类
                  Interceptor interceptor = element.getAnnotation(Interceptor.class);
                  // 先从缓存中获取,如果不为空,即设置了相同优先级的拦截器,会抛异常
                  // 这里就解释了为什么设置相同优先级会报错
                  Element lastInterceptor = interceptors.get(interceptor.priority());
                  if (null != lastInterceptor) { // Added, throw exceptions
                      throw new IllegalArgumentException(
                              String.format(Locale.getDefault(), "More than one interceptors use same priority [%d], They are [%s] and [%s].",
                                      interceptor.priority(),
                                      lastInterceptor.getSimpleName(),
                                      element.getSimpleName())
                      );
                  }
                  // 添加到缓存中
                  interceptors.put(interceptor.priority(), element);
              } else {
                  logger.error("A interceptor verify failed, its " + element.asType());
              }
          }

          // Interface of ARouter.
          // IInterceptor 接口
          TypeElement type_ITollgate = elementUtils.getTypeElement(IINTERCEPTOR);
          // IInterceptorGroup 接口
          TypeElement type_ITollgateGroup = elementUtils.getTypeElement(IINTERCEPTOR_GROUP);

           // 构建 Map<Integer, Class<? extends IInterceptor>>
          ParameterizedTypeName inputMapTypeOfTollgate = ParameterizedTypeName.get(
                  ClassName.get(Map.class),
                  ClassName.get(Integer.class),
                  ParameterizedTypeName.get(
                          ClassName.get(Class.class),
                          WildcardTypeName.subtypeOf(ClassName.get(type_ITollgate))
                  )
          );

          // Build input param name.
          // 构建成 Map<Integer, Class<? extends IInterceptor>> interceptors
          ParameterSpec tollgateParamSpec = ParameterSpec.builder(inputMapTypeOfTollgate, "interceptors").build();

          // Build method : 'loadInto'
          // 构建方法 loadInto
          MethodSpec.Builder loadIntoMethodOfTollgateBuilder = MethodSpec.methodBuilder(METHOD_LOAD_INTO)
                  .addAnnotation(Override.class)
                  .addModifiers(PUBLIC)
                  .addParameter(tollgateParamSpec);

          // Generate
          if (null != interceptors && interceptors.size() > 0) {
              // Build method body
              for (Map.Entry<Integer, Element> entry : interceptors.entrySet()) {
                  // 构建方法内容
                  loadIntoMethodOfTollgateBuilder.addStatement("interceptors.put(" + entry.getKey() + ", $T.class)", ClassName.get((TypeElement) entry.getValue()));
              }
          }

          // Write to disk(Write file even interceptors is empty.)
          // 生成类并写入硬盘
          JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                  TypeSpec.classBuilder(NAME_OF_INTERCEPTOR + SEPARATOR + moduleName)
                          .addModifiers(PUBLIC)
                          .addJavadoc(WARNING_TIPS)
                          .addMethod(loadIntoMethodOfTollgateBuilder.build())
                          .addSuperinterface(ClassName.get(type_ITollgateGroup))
                          .build()
          ).build().writeTo(mFiler);

          logger.info(">>> Interceptor group write over. <<<");
      }
  }

该处理器主要做了以下操作:

  1. 找到所有的 Interceptor 注解元素并进行检验。
  2. 判断是否有相同优先级的拦截器,有则抛异常,没有则把当前元素放入缓存。
  3. 利用 poet 库进行参数的构建、方法的构建和类的构建。

以下是一个通过该注解处理器生成的类:

// 实现 IInterceptorGroup 接口
public class ARouter$$Interceptors$$app implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    // key 是优先级,value 是对应的拦截器的 Class 类型
    interceptors.put(8, TestInterceptor.class);
  }
}

实际上生成的类的类名是 ARouter$$Interceptors$$xxx 形式的,最后的名称是对应的模块名(moduleName) ,我这里是在 app 模块,所以后面的 xxxapp

RouteProcessor

该处理器主要是处理路由的,即处理 Route 注解,具体的操作类似于拦截器,最终会生成如下几种不同的类:

ARouter$$Providers$$app

实际上生成的类的类名是 ARouter$$Providers$$xxx ,最后的名称对应的模块名(moduleName)

// 实现 IProviderGroup 接口
public class ARouter$$Providers$$app implements IProviderGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> providers) {
    // key 是服务接口的全类名,value 是一个 RouteMeta 类
    providers.put("com.alibaba.android.arouter.facade.service.DegradeService", RouteMeta.build(RouteType.PROVIDER, DegradeServiceImpl.class, "/service/degrade", "service", null, -1, -2147483648));
    providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/service/json", "service", null, -1, -2147483648));
    providers.put("com.alibaba.android.arouter.facade.service.PretreatmentService", RouteMeta.build(RouteType.PROVIDER, PretreatmentServiceImpl.class, "/service/pretreatment", "service", null, -1, -2147483648));
    providers.put("com.fanda.zeng.arouterdemo.service.TestService", RouteMeta.build(RouteType.PROVIDER, TestServiceImpl.class, "/service/testService", "service", null, -1, -2147483648));
  }
}

ARouter$$Root$$app

同理,类名最后面的 app 是模块名称,不同模块名称不一样。

// 实现 IRouteRoot 接口
public class ARouter$$Root$$app implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    // key 是分组名称,value 是对应的组的索引类 
    routes.put("service", ARouter$$Group$$service.class);
    routes.put("test", ARouter$$Group$$test.class);
  }
}

这个类体现了按需加载的方案,这是一个分组的 Root 类,负责管理所有的分组的索引类,当需要加载对应的组时,会找到相应的索引类,然后把索引类下面保存的所有页面路由加载进内存。

ARouter$$Group$$test

类名最后面的 test 是分组的名称,不同的分组不一样

// 实现 IRouteGroup 接口
public class ARouter$$Group$$test implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    // key 是路由地址 ,value 是 RouteMeta 类
    atlas.put("/test/Test1Activity", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/test1activity", "test", null, -1, -2147483648));
    atlas.put("/test/Test2Activity", RouteMeta.build(RouteType.ACTIVITY, Test2Activity.class, "/test/test2activity", "test", new java.util.HashMap<String, Integer>(){{put("url", 8); }}, -1, -2147483648));
    atlas.put("/test/Test3Activity", RouteMeta.build(RouteType.ACTIVITY, Test3Activity.class, "/test/test3activity", "test", new java.util.HashMap<String, Integer>(){{put("testObjList", 11); put("testObj", 11); put("teacherName", 8); put("testPac", 10); put("testMap", 11); put("age", 3); }}, -1, 100));
    atlas.put("/test/Test4Activity", RouteMeta.build(RouteType.ACTIVITY, Test4Activity.class, "/test/test4activity", "test", null, -1, -2147483648));
    atlas.put("/test/TestFragment", RouteMeta.build(RouteType.FRAGMENT, TestFragment.class, "/test/testfragment", "test", null, -1, -2147483648));
    atlas.put("/test/webview", RouteMeta.build(RouteType.ACTIVITY, TestWebviewActivity.class, "/test/webview", "test", new java.util.HashMap<String, Integer>(){{put("url", 8); }}, -1, -2147483648));
  }
}

AutowiredProcessor

该处理器是用来处理 Autowired 注解的,用于生成数据自动注入的辅助类,自动注入时需要调用如下方法:

ARouter.getInstance().inject(this);

其实就是调用这里生成的辅助类的 inject 方法,我们看一下生成的类:

// 实现 ISyringe 接口
public class Test3Activity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    // 获取自定义对象解析服务类
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    Test3Activity substitute = (Test3Activity)target;
    // 字段赋值,不用是私有
    substitute.name = substitute.getIntent().getStringExtra("teacherName");
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
    substitute.testPac = substitute.getIntent().getParcelableExtra("testPac");
    if (null != serializationService) {
        // 进行解析处理
      substitute.testObj = serializationService.parseObject(substitute.getIntent().getStringExtra("testObj"), new com.alibaba.android.arouter.facade.model.TypeWrapper<TestObj>(){}.getType());
    } else {
        // 没有提供解析服务类,打印异常
      Log.e("ARouter::", "You want automatic inject the field 'testObj' in class 'Test3Activity' , then you should implement 'SerializationService' to support object auto inject!");
    }
  }
}

先看一下该类的类名生成规则 Test3Activity$$ARouter$$Autowired ,很明显,最前面一段是对应的 ActivityFragment 的名称,后面的是写死的模板名称。这里的赋值操作也说明了需要注入的字段不能是私有的,对于自定义的对象,需要 serializationService 进行解析。这个辅助类只是帮我们从 IntentBundle 中取出数据并进行赋值操作,如果不需要,完全可以自己手写赋值代码。

前面提到在 Providers 中保存的 value 和在分组索引的 value 中保存的都是 RouteMeta 类:

 atlas.put("/test/Test1Activity", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/test1activity", "test", null, -1, -2147483648));

 atlas.put("/test/Test1Activity", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/test1activity", "test", null, -1, -2147483648));

put("/test/TestFragment", RouteMeta.build(RouteType.FRAGMENT, TestFragment.class, "/test/testfragment", "test", null, -1, -2147483648));

那么我们看一下 RouteMeta 的字段:

public class RouteMeta {
    private RouteType type;         // Type of route,路由类型
    private Element rawType;        // Raw type of route
    private Class<?> destination;   // Destination,路由目标的 Class 类型
    private String path;            // Path of route,路由地址
    private String group;           // Group of route,路由分组
    private int priority = -1;      // 优先级,越小优先级越大
    private int extra;              // 额外的数据
    private Map<String, Integer> paramsType;  // Param type
    private String name;    // 在 Route 注解的 name 方法设置
}

其中 paramsType 是包含了所有注解了 Autowired 的属性的信息,key 为属性名,value 为属性类型,ARouter 将可被 intent 传递的数据类型定义了对应的 int 类型: BOOLEAN,BYTE,SHORT,INT,LONG,CHAR,FLOAT,DOUBLE,STRING,PARCELABLE,OBJECT 分别对应 0,1,2,3…

RouteType 是一个枚举,表示被注解类的路由类型:

public enum RouteType {
    ACTIVITY(0, "android.app.Activity"),
    SERVICE(1, "android.app.Service"),
    PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
    CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
    BOARDCAST(-1, ""),
    METHOD(-1, ""),
    FRAGMENT(-1, "android.app.Fragment"),
    UNKNOWN(-1, "Unknown route type");
}

目前支持的是 ACTIVITYPROVIDERFRAGMENTACTIVITYFRAGMENT 是用来做路由跳转的,PROVIDER 用于提供服务实例的,用于模块解耦,这些类型的用法在 ARouter 使用篇已经讲过。